/* 
Scenic Graphics Library
Copyright (C) 2007 Jouni Tulkki

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USApackage scenic;
*/

#include "common.h"


using namespace Scenic::Renderer;


extern ResourcePool imagePool;

ResourcePool contextPool("Context");


ClipArea::ClipArea()
{
	parent = NULL;
	surface = NULL;
	texture = NULL;
}

ClipArea::~ClipArea()
{
	if(surface)
		surface->release();
	if(texture)
		texture->release();
}

Context::Context(Canvas *canvas)
: Resource(&contextPool)
{
	this->canvas = canvas;
	image = NULL;
	device = canvas->device;
	init();
}

Context::Context(Image *image)
: Resource(&contextPool)
{
	canvas = NULL;
	this->image = image;
	device = Device::getDefaultDevice();
	init();
}

Context::~Context()
{
	if(insideScene)
	{
		printf("Context::~Context : within scene\n");
	}
	freeDeviceResources();
}

void Context::init()
{
	aaPolygonTexture = NULL;
	polygonAntialias = false;
	filterKernel = NULL;
	primitives = NULL;
	insideScene = false;
	clip = NULL;
}

void Context::freeDeviceResources()
{
	if(aaPolygonTexture)
		aaPolygonTexture->release();
}

void Context::setPrimitives(Primitives *p)
{
	if(primitives == p)
		return;
	if(primitives)
		primitives->setContext(NULL);
	primitives = p;
	if(primitives)
		primitives->setContext(this);
}

Context *Scenic::Renderer::getContext(int id)
{
	return (Context*)contextPool.get(id);
}

void Context::setRenderTarget(Surface *target)
{
	SurfaceInfo info = target->getInfo();

	device->setRenderTarget(target);
	initializeViewport(info.width, info.height);
}

void Context::initializeViewport(int width, int height)
{
	device->initializeViewport(width, height);
}

bool Context::beginScene()
{
	if(insideScene)
	{
		printf("Context::beginScene() : inside scene\n");
	}
	insideScene = true;
	originalRenderTarget = device->getRenderTarget();

	if(!device->beginScene())
	{
		return false;
	}

	if(canvas)
	{
		Surface *surface = device->getRenderTarget();
		SurfaceInfo info = surface->getInfo();
		
		initializeViewport(info.width, info.height);
		clip = new ClipArea();
		clip->x = 0;
		clip->y = 0;
		clip->width = info.width;
		clip->height = info.height;
		clip->offsetX = 0;
		clip->offsetY = 0;
		clip->surface = surface;
		clip->texture = 0;
		clip->type = SURFACE_TYPE_COLOR;
		clip->linearColorSpace = false;
	}
	else
	{
		clip = new ClipArea();
		clip->x = 0;
 		clip->y = 0;
		clip->width = image->width;
		clip->height = image->height;
		clip->offsetX = 0;
		clip->offsetY = 0;
		clip->type = SURFACE_TYPE_COLOR;
		clip->texture = image->getBlock(0, 0)->texture;
		clip->texture->addRef();
		clip->surface = clip->texture->getSurface(0);
		clip->linearColorSpace = false;
		
		setRenderTarget(clip->surface);
	}

	width = clip->width;
	height = clip->height;

	return true;
}

void Context::endScene()
{
	if(!insideScene)
	{
		printf("Context::endScene() : outside scene\n");
	}
	insideScene = false;
	setPrimitives(NULL);
	device->endScene();
	while(clip)
	{
		ClipArea *c = clip->parent;

		delete clip;
		clip = c;
	}
	if(originalRenderTarget)
	{
		setRenderTarget(originalRenderTarget);
		originalRenderTarget->release();
		originalRenderTarget = NULL;
	}
}
